#ifndef OPTIONS_H
#define OPTIONS_H
#ifdef __cplusplus
#include "enum_def.hpp"
#endif

//用来生成当前选择的编程语言的编译命令和执行命令

// 语言类型分类
#define NONE_LANGUAGE           64
#define COMPILE_LANGUAGE        1
#define INTERPRETER_LANGUAGE    2
#define DATABASE_LANGUAGE       4
#ifdef __cplusplus
DECLARE_OPTION_BLOCK(int, LANGUAGE_TYPE,
                        NONE_LANGUAGE,
                        COMPILE_LANGUAGE,
                        INTERPRETER_LANGUAGE,
                        DATABASE_LANGUAGE
                    )
DECLARE_FIND_OPTION_NAME_DEFAULT(LANGUAGE_TYPE)
DECLARE_FIND_MULTI_OPTION_NAME_DEFAULT(LANGUAGE_TYPE)
#endif

//根据不同的精度或忽略换行等场景进行文件比对
#define STRICT_CNSISTENT 0      //严格一致,该选项应该是独立的，不能与其他选项共存
#define ALLOW_PRECISION_ERROR 2 //允许存在精度误差
#define IGNORE_END_BLANK 4      //忽略每行换行符前的空白符，并且会忽略最后一个可见字符之后的一切空白字符
#define IGNORE_ALL_BLANK 8      //忽略一切空白符，只比较非空白符
#define IGNORE_CASE 16          //忽略大小写
#define IGNPRE_LIST_ORDER 32    //允许json对象中两个列表支持乱序比较，仅支持最高维的列表操作，最高维以下的列表将不再支持乱序，可用于sql中select查询结果未order by时防止查询顺序出现小概率不一致
#define JSONOBJECT_COMPARE 128  //比对json文本中建立的json对象是否一致

#ifdef __cplusplus
DECLARE_OPTION_BLOCK(int, COMPARE_TYPE,
                        STRICT_CNSISTENT,
                        ALLOW_PRECISION_ERROR,
                        IGNORE_END_BLANK,
                        IGNORE_ALL_BLANK,
                        IGNORE_CASE,
                        IGNPRE_LIST_ORDER,
                        JSONOBJECT_COMPARE
                    )
DECLARE_FIND_OPTION_NAME_DEFAULT(COMPARE_TYPE)
DECLARE_FIND_MULTI_OPTION_NAME(COMPARE_TYPE, std::string("|"), [](auto&& target, auto&& option) {
    int x = static_cast<int>(target);
    int y = static_cast<int>(option);
    return ( (x == y) || (x & y) );
})
#endif


// 此参数为ruler
// 在runJudge函数中会被截断为两部分,二进制后五位表示赛制,其余位数表示赛制选项
// 赛制相关
#define ACM_CONTENT 1
#define OI_CONTENT 2


#ifdef __cplusplus
// 这几个选项为赛制的附加选项,可多选
// 返回的结果结构体中的output是每一次样例运行的输出结果,表现为列表形式
DECLARE_OPTION_BLOCK(int, CONTENT_TYPE, ACM_CONTENT, OI_CONTENT)
DECLARE_FIND_OPTION_NAME_DEFAULT(CONTENT_TYPE)
#endif


#define RETURN_FIRST_OUTPUT (1 << 0)
// 返回的结果结构体中的extern_info的first_wrong_output字段是第一次run/verify失败时的输出结果,但会被限制长度在MAX_OUTLIMIT
#define RETURN_FIRST_WRONG_OUTPUT (1 << 1)
// 返回的结果结构体中的extern_info的first_wrong_input字段是第一次run/verify失败时的输入样例(字符串类型)
#define RETURN_FIRST_WRONG_INPUT (1 << 2)
// 返回的结果结构体中的extern_info的first_wrong_stdout字段是第一次run/verify失败时的标准输出结果(字符串类型)
#define RETURN_FIRST_WRONG_STDOUT (1 << 3)
// 返回的结果结构体中的extern_info的result_list字段中新增time,memory,result,error字段
// 如[{"time" : 1, "memory" : 12345678, "result" : "AC"}, ...]
#define RETURN_ALL_RESULT (1 << 4)
// 返回的结果结构体中的extern_info的result_list字段中新增output字段表示用户代码的输出结果
#define RETURN_ALL_OUTPUT (1 << 5)
// 返回的结果结构体中的extern_info的result_list字段中新增stdout字段表示标称代码的输出结果
#define RETURN_ALL_STDOUT (1 << 6)
// 返回的结果结构体中的extern_info的result_list字段中新增example_in字段表示输入用的测试用例
#define RETURN_ALL_EXAMPLE_IN (1 << 7)

#ifdef __cplusplus
DECLARE_OPTION_BLOCK(int, QUERY_SET_TYPE,
                        RETURN_FIRST_OUTPUT,
                        RETURN_FIRST_WRONG_OUTPUT,
                        RETURN_FIRST_WRONG_INPUT,
                        RETURN_FIRST_WRONG_STDOUT,
                        RETURN_ALL_RESULT,
                        RETURN_ALL_OUTPUT,
                        RETURN_ALL_STDOUT,
                        RETURN_ALL_EXAMPLE_IN
                    )
DECLARE_FIND_OPTION_NAME_DEFAULT(QUERY_SET_TYPE)
DECLARE_FIND_MULTI_OPTION_NAME_DEFAULT(QUERY_SET_TYPE)
#endif


// 题目类型相关
// 常规判题
#define NORMAL_JUDGE 0
// 交互题
#define INTERACTIVE_JUDGE 1
// 特判题
#define SPECIAL_JUDGE 2
// 数据库查询题型
#define DATABASE_SELECT_JUDGE 3
// 数据库增删改题型
#define DATABASE_MODIFY_JUDGE 4
// 模块题型
#define MODULE_JUDGE 5

#ifdef __cplusplus
DECLARE_OPTION_BLOCK(int, PROBLEM_TYPE,
                        NORMAL_JUDGE,
                        INTERACTIVE_JUDGE,
                        SPECIAL_JUDGE,
                        DATABASE_SELECT_JUDGE,
                        DATABASE_MODIFY_JUDGE,
                        MODULE_JUDGE
                    )
DECLARE_FIND_OPTION_NAME_DEFAULT(PROBLEM_TYPE)
#endif

// 输入输出相关
#define MAX_PIPEBUFF 1024
const int OUTPUT_FILE_MAXSIZE = 20 * 1024 * 1024;
const int MAX_OUTLIMIT = 20 * 1024;
const int OUTPUT_BUFF_MAXSIZE = 20 * 1024;

// 尽量在255以下，132以上
#define RUN_OK 0
#define TLE 150
#define MLE 152
#define WA 153
#define PE 154
#define SYS_ERROR 155
#define OLE 156
#define SYS_CHECK 157
#define CONTINUE 158
#define RUN_FAIL 160
#define LESS_STDFILES 161
#define LESS_SPJFILE 162
#define SPJFILE_COMPILE_ERROR 163
#define WAIT_JUDGE 164
#define SPJFILE_RUN_ERROR 165
#define RE 166
#define UNKNOWN_JUDGE_TYPE 167
#define CE 200
#define CETLE 167
#define SETRLIMIT_TIME_ERROR 168
#define SETRLIMIT_STACK_ERROR 169
#define SETRLIMIT_FSIZE_ERROR 170
#define SETRLIMIT_VMEM_ERROR 171
#define SETRLIMIT_AS_ERROR 172
#define SETRLIMIT_RSS_ERROR 173
#define SETITIMER_ITIMER_VIRTUAL 174
#define SETITIMER_ITIMER_REAL 175
#define SETITIMER_ITIMER_PROF 176
#define MALLOC_ERROR 177
#define SIGALTSTACK_ERROR 178
#define SIGACTION_ERROR 179
#define PARAMS_ERROR 180
#define PIPE_ERROR 181
#define STD_COMPILE_ERROR 182
#define MYSQL_ERROR 190
#define NO_ACTION_EVENT 200
#define UNKNOWN_EVENT 250
#define END_EVENT 251


// 用于进程控制
// 不跟踪该子进程
#define NO_PTRACE 1
// 不进行system_call检查,默认进行检查
#define NON_SYSCHECK 2
// 设置为root用户,默认为nobody用户执行
#define NON_NOBODY 4
#ifdef __cplusplus
DECLARE_OPTION_BLOCK(int, EXEC_PERMIT, NO_PTRACE, NON_SYSCHECK, NON_NOBODY)
DECLARE_FIND_OPTION_NAME_DEFAULT(EXEC_PERMIT)
#endif

const int COMPILE_TIME_LIMIT = 2 * 1000;

#ifdef __cplusplus
#include <chrono>
const auto ZONE_TIME = std::chrono::hours(0);
#endif

#endif